home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 2.iso / BARNET / COMPILER / SATHER / !Sather / Library / Containrs / sa / fset < prev    next >
Text File  |  1996-06-01  |  17KB  |  585 lines

  1. ---------------------------> Sather 1.1 source file <--------------------------
  2. -- Version which typecases for FLIST routines
  3. -- Copyright (C) International Computer Science Institute, 1994.  COPYRIGHT  --
  4. -- NOTICE: This code is provided "AS IS" WITHOUT ANY WARRANTY and is subject --
  5. -- to the terms of the SATHER LIBRARY GENERAL PUBLIC LICENSE contained in    --
  6. -- the file "Doc/License" of the Sather distribution.  The license is also   --
  7. -- available from ICSI, 1947 Center St., Suite 600, Berkeley CA 94704, USA.  --
  8. --------> Please email comments to "sather-bugs@icsi.berkeley.edu". <----------
  9. -- Nasty things about switch threshold - it depends on the initial
  10. -- size - switch at the first doubling.
  11. -- However, initial size seems to be determined differently at different
  12. -- points in the code...
  13. -- double_size does the actual switching from list to map
  14. -- Does NOT shrink on the way down (after deletes)
  15. -- ffset.sa: Hash-based sets of objects of type T.
  16. -------------------------------------------------------------------
  17. class FSET{T} < $COPY is
  18.    -- Faster (hopefully!) version of FSET that switches from an FLIST
  19.    -- to an FSET at the first amortized doubling. 
  20.        -- Hash array based sets of objects of type T requiring writebacks.
  21.     -- 
  22.     -- If T is a subtype of $NIL, then `nil' may not be an element,
  23.     -- otherwise the type's default value may not be a element.
  24.     -- 
  25.     -- If T is a subtype of $IS_EQ, then `is_eq' will be used for
  26.     -- element equality (eg. string equality for STR), otherwise 
  27.     -- object equality is used. 
  28.     -- 
  29.     -- If T is a subtype of $HASH, then `hash' will be used for the hash
  30.     -- value, otherwise the element `id' will be used.
  31.     -- 
  32.     -- May be inherited with `elt_eq', `elt_nil', and `elt_hash' redefined
  33.     -- to get a different behavior.
  34.     --
  35.     -- The tables grow by amortized doubling and so require writeback
  36.     -- when inserting and deleting elements.  We keep down the load
  37.     -- factor to cut down on collision snowballing.  The simple
  38.     -- collision resolution allows us to support deletions, but makes
  39.     -- the behavior with poor hash functions quadratic.  Puts a
  40.     -- sentinel at the end of the table to avoid one check while
  41.     -- searching.
  42.    -- See the notes associated with an ORIG_FSET.
  43.    -- For laziness reasons, the old FSET has been renamed to ORIG_FSET
  44.    --  (slow fset)
  45.    include COMPARE{T};
  46.    include AREF{T};
  47.  
  48.    private const use_map_initially: BOOL := false;
  49.    -- Indicates whether the data structure 
  50.    -- should start out with a map
  51.    private const switch_structures: BOOL := true;
  52.    -- Indicates whether the data structure 
  53.    -- should switch after the first allocate
  54.    
  55.    private attr hsize:INT;    -- Number of stored entries.
  56.    readonly attr use_map: BOOL;    -- True if using the space as a map
  57.    private const default_initial_size: INT := 5;
  58.    --shared upward_transition_size: INT;
  59.    -- shared downward_transition_size: INT;
  60.    private const load_ratio:INT:=4; -- Allow to be at most 1/load_ratio full
  61.  
  62.    create:SAME is return void end;
  63.    
  64.    create(n:INT):SAME 
  65.    -- Make a table capable of dealing with `n' elements without
  66.    -- expansion. You can simply insert into a void table to create 
  67.    -- one as well. Self may be void (and often is).
  68.       pre n>=1 is 
  69.       res ::= allocate(1.lshift((3*load_ratio*n/4).highest_bit+1)+1);
  70.       res.set_initial_structure;
  71.       return res;
  72.    end;
  73.  
  74.    create(arr: ARRAY{T}): SAME is return create_from(arr) end;
  75.    
  76.    create_from(a: $CONTAINER{T}): SAME is
  77.       res: SAME := #(a.size);
  78.       loop res := res.insert(a.elt!) end;
  79.       return res;
  80.    end;
  81.    
  82.    private allocate(n:INT):SAME is
  83.       -- Allocate `n' locations (must be power of 2 plus 1) and
  84.       -- initialize to `elt_nil'.
  85.       r::=new(n); 
  86.       if ~void(elt_nil) then 
  87.      loop r.aset!(elt_nil) end 
  88.       end;
  89.       return r
  90.    end;
  91.    
  92.    size:INT is
  93.       -- Number of entries in the table. Self may be void.
  94.       if void(self) then return 0 
  95.       else return hsize 
  96.       end 
  97.    end;
  98.  
  99.    copy:SAME is
  100.       -- A copy of self.
  101.       r:SAME; 
  102.       loop r:=r.insert(elt!) end;
  103.       return r
  104.    end;
  105.    
  106.    elt!:T is
  107.       -- Yield the elements in self in an arbitrary order. Do not insert
  108.       -- or delete from self while calling this. Self may be void.
  109.       if ~void(self) then 
  110.      if use_map then
  111.         loop r::=aelt!; 
  112.            if ~is_elt_nil(r) then yield r end
  113.         end
  114.      else 
  115.         i ::= 0; sz ::= hsize;
  116.         loop until!(i = hsize); yield [i]; i := i + 1; end;
  117.      end;
  118.       end
  119.    end;
  120.  
  121.    first_elt:T is
  122.       -- The first element in the table, if any, otherwise elt_nil.
  123.       if ~void(self) then 
  124.      if use_map then
  125.         loop r::=aelt!; 
  126.            if ~is_elt_nil(r) then return r end 
  127.         end
  128.      elsif hsize > 0 then return [0] end;
  129.       end;
  130.       return elt_nil 
  131.    end;
  132.    
  133.    has(e: T): BOOL is return test(e) end;
  134.    
  135.    test(e:T):BOOL is
  136.       -- True if `e' is `elt_eq' to an element contained in self. 
  137.       -- Self may be void.
  138.       if void(self) then return false end;  
  139.       if use_map then return test_map(e) 
  140.       else return test_list(e) end;
  141.    end;
  142.     
  143.    test_list(e: T): BOOL is
  144.       i ::= 0; sz ::= hsize;
  145.       loop  until!(i = sz); 
  146.      if elt_eq(e,[i]) then return true end;
  147.      i := i + 1;
  148.       end;
  149.       return false;
  150.    end;
  151.  
  152.    private set_initial_structure is
  153.       use_map := use_map_initially;
  154.    end;
  155.    
  156.    private switch_structure(is_old_map: BOOL, is_new_map: BOOL) is
  157.       -- Isolate this as a function to make changes easier
  158.       if switch_structures then use_map := is_new_map
  159.       else use_map := is_old_map; end;
  160.    end;
  161.    
  162.    test_map(e: T): BOOL is
  163.       h::=elt_hash(e).band(asize-2);
  164.       loop te::=[h];  
  165.      if is_elt_nil(te) then break!
  166.      elsif elt_eq(te,e) then return true
  167.      end;  
  168.      h:=h+1 end;
  169.       if h=asize-1 then        -- hit sentinel
  170.      h:=0;
  171.      loop te::=[h];
  172.         if is_elt_nil(te) then break!
  173.         elsif elt_eq(te,e) then return true
  174.         end;  
  175.         h:=h+1 
  176.      end;
  177.      assert h/=asize-1 -- table mustn't be filled
  178.       end; 
  179.       return false 
  180.    end;
  181.    
  182.    get(e:T):T is
  183.       -- If `e' is `elt_eq' to a table entry, return that entry, 
  184.       -- otherwise return `elt_nil'. Useful when different objects 
  185.       -- are treated as equal (eg. a table of strings used to get a 
  186.       -- unique representative for each class of equal strings).
  187.       -- Self may be void.
  188.       if void(self) then return elt_nil end;
  189.       if use_map then return get_map(e)
  190.       else return get_list(e); end;
  191.    end;
  192.  
  193.    get_list(e: T): T is
  194.       i ::= 0; sz ::= hsize;
  195.       loop  until!(i = sz); 
  196.      if elt_eq(e,[i]) then return [i] end;
  197.      i := i + 1;
  198.       end;
  199.       return elt_nil
  200.    end;
  201.  
  202.    get_map(e: T): T is
  203.       h::=elt_hash(e).band(asize-2);    
  204.       loop te::=[h];
  205.      if is_elt_nil(te) then break!
  206.      elsif elt_eq(te,e) then return te
  207.      end;
  208.      h:=h+1 
  209.       end;
  210.       if h=asize-1 then h:=0;    -- hit sentinel
  211.      loop te::=[h];
  212.         if is_elt_nil(te) then break!
  213.         elsif elt_eq(te,e) then return te
  214.         end;
  215.         h:=h+1 
  216.      end;
  217.      assert h/=asize-1 -- table mustn't be filled
  218.       end; 
  219.       return elt_nil 
  220.    end;
  221.    
  222.    private double_size:SAME 
  223.    -- A new table of twice the size of self with self's entries
  224.    -- copied over. 
  225.       pre ~void(self) is
  226.       r::=allocate((asize-1)*2+1); 
  227.       r.switch_structure(use_map,true);
  228.       assert changed_map(self,r);
  229.       loop 
  230.      -- test if the has values have changed (should never happen)
  231.      assert test(elt!);
  232.          r:=r.insert(elt!);
  233.       end;
  234.       SYS::destroy(self);   -- The old set should never be used now.
  235.       return r
  236.    end;
  237.  
  238.    changed_map(old,n: SAME): BOOL is
  239.       -- if ~old.use_map and n.use_map then
  240. --     #OUT+"Transitioning to use map. Size="+old.size+"\n";
  241.  --     end;
  242.       return true;
  243.    end;
  244.  
  245.    private grow_if_necc: SAME is
  246.       -- Return a new map if it is necessary to grow it, otherwise
  247.       -- return self
  248.       if use_map then
  249.      if (hsize+1)*load_ratio>asize then
  250.         return double_size;
  251.      else return self end;
  252.       else
  253.      -- Still using list. Different growth condition
  254.      if hsize >= asize then  return double_size 
  255.         -- Must grow, which causes a transition
  256.      else return self end;
  257.       end;
  258.    end;
  259.  
  260.    insert(e:T):SAME is
  261.       -- A possibly new table which includes `e'. If an entry 
  262.       -- is `elt_eq' to `e' then overwrite it with `e'.
  263.       -- Usage: `tbl:=tbl.insert(e)'. 
  264.       -- Creates a new table if void(self).
  265.       r::=self;
  266.       if void(r) then 
  267.      r:=allocate(default_initial_size); 
  268.      r.set_initial_structure;
  269.       else r:=grow_if_necc end;
  270.       if r.use_map then return insert_hash(r,e); 
  271.       else return insert_list(r,e) end;
  272.    end;
  273.  
  274.    insert_list(r: SAME,e:T): SAME is
  275.       -- If this is called, there should be at least enough space
  276.       -- for one more insert
  277.       -- Check for existing element first
  278.       i ::= 0; sz ::= r.hsize;
  279.       loop until!(i=sz);
  280.      if elt_eq(e,r[i]) then r[i] := e; return r end;
  281.      i := i + 1;
  282.       end;
  283.       -- Otherwise insert into the last position
  284.       r[r.hsize] := e;
  285.       r.hsize := r.hsize+1;
  286.       return r;
  287.    end;
  288.  
  289.    insert_hash(r: SAME,e:T): SAME is
  290.       asz::=r.asize;
  291.       orig_h::=r.elt_hash(e).band(asz-2);
  292.       h::=orig_h;
  293.       loop te::=r[h];
  294.      if is_elt_nil(te) then break!
  295.      elsif elt_eq(te,e) then r[h]:=e; 
  296.         return r 
  297.      end;
  298.      h:=h+1 
  299.       end;
  300.       if h=asz-1 then        -- Look through whole table from beginning
  301.      -- until you find at least one blank element.
  302.      h:=0;    -- hit sentinel
  303.      loop te::=r[h];
  304.         if is_elt_nil(te) then break!
  305.         elsif elt_eq(te,e) then r[h]:=e;     return r   end;
  306.         h:=h+1 
  307.      end;
  308.      assert h/=asz-1 
  309.       end; -- table mustn't be filled    
  310.       assert not_too_many(orig_h,h); -- Look for excessive collisions
  311.       r[h]:=e; 
  312.       r.hsize:=r.hsize+1; 
  313.       return r 
  314.    end;
  315.  
  316.    private not_too_many(start, finish:INT):BOOL is
  317.       -- A function called in an assert to check that really
  318.       -- bad hashing isn't happening, which would probably
  319.       -- be a performance bug.  Since it is in an assert, this
  320.       -- isn't called unless checking is on.
  321.       if finish>start+50 then
  322.      #ERR+"Found a problem: excessive collisions in "
  323.            +SYS::str_for_tp(SYS::tp(self))
  324.            +", probably\n"
  325.            +"due to a bad hash function in the class "
  326.            +SYS::str_for_tp(SYS::tp([start]))
  327.            +".\n";
  328.      #ERR + "Snowballing values:\n";
  329.      i ::= 0; last ::= finish-1;
  330.      loop until!(i = finish-1);
  331.         -- i::=start.upto!(finish-1);
  332.         e::=[i];
  333.         h::=elt_hash(e);
  334.         #ERR + i + '\t' + h.hex_str + '\t' + h.band(asize-2);
  335.         if void(e) then #ERR+" Void elt" ;
  336.         else
  337.            tp ::= SYS::tp(e);
  338.            tp_str ::= SYS::str_for_tp(tp);
  339.            #ERR+" Type:"+tp_str;
  340.            -- typecase e
  341.            -- when $AM then #ERR+ " Source:"+e.source.str+" "; else end;
  342.         end;
  343.         typecase e when $STR then #ERR + '\t' + e.str.pretty; else end;
  344.         #ERR+'\n';
  345.         i := i + 1;
  346.      end;
  347.      return false;
  348.       end;
  349.       return true;
  350.    end;
  351.    
  352.    private halve_size:SAME pre ~void(self) and hsize<(asize-1)/4 is
  353.       -- A new table of half the size of self with self's entries
  354.       -- copied over. 
  355.       -- For now, don't transition downward
  356.       r::=allocate((asize-1)/2+1);
  357.       r.switch_structure(use_map,true);
  358.       loop r:=r.insert(elt!) end;
  359.       SYS::destroy(self);   -- The old set should never be used now.
  360.       return r
  361.    end;
  362.  
  363.    private should_shrink:BOOL is
  364.       return asize>=33 and hsize<(asize-1)/(load_ratio*2);
  365.    end;
  366.    
  367.    delete(e:T):SAME is
  368.       -- A possibly new table which deletes the element `e' if it is
  369.       -- contained in self. Doesn't modify the table if arg is not
  370.       -- contained. Usage: `tbl:=tbl.delete(e)'.  Self may be void.
  371.       if void(self) then return void end;
  372.       if use_map then return delete_map(e) 
  373.       else return delete_list(e) end;
  374.       
  375.    end;
  376.  
  377.    delete_list(e: T): SAME is
  378.       delete_elt_ind:INT := -1;
  379.       hash_table_size:INT := hsize;
  380.       i:INT := 0; 
  381.       loop until!(i >= hash_table_size); 
  382.      if elt_eq(e,[i]) then delete_elt_ind := i; break!;  end;
  383.      i := i + 1;
  384.       end;
  385.       if 0 <= delete_elt_ind  and delete_elt_ind < hsize then
  386.      empty_loc: INT := delete_elt_ind; 
  387.      second_to_last_index: INT := hsize - 2;
  388.      -- Empty_loc goes from the delete element index to the pre-last elt
  389.      loop until!(empty_loc > second_to_last_index);
  390.         next: INT := empty_loc+1;
  391.         [empty_loc] := [next];
  392.         empty_loc := next;
  393.      end;
  394.      hsize := hsize - 1;
  395.       end;
  396.       return self;
  397.    end;
  398.  
  399.    delete_map(e: T): SAME is
  400.       h::=elt_hash(e).band(asize-2);
  401.       loop 
  402.      te::=[h];
  403.      if is_elt_nil(te) then return self
  404.      elsif elt_eq(te,e) then break!
  405.      end;
  406.      if h=asize-2 then h:=0 
  407.      else h:=h+1 
  408.      end 
  409.       end;
  410.       [h]:=elt_nil; 
  411.       hsize:=hsize-1; 
  412.       i::=h; -- h is the index of arg
  413.       -- Now check the block after h for collisions.
  414.       loop 
  415.      if i=asize-2 then i:=0 
  416.      else i:=i+1
  417.      end;
  418.      te::=[i];
  419.      if is_elt_nil(te) then break! end;
  420.      hsh::=elt_hash(te).band(asize-2);
  421.      if hsh<=i then        -- block doesn't wrap around
  422.         if h<i and h>=hsh then -- hole in way
  423.            [h]:=[i]; 
  424.            h:=i; 
  425.            [i]:=elt_nil
  426.         end
  427.      else            -- block wraps
  428.         if h>=hsh or h<i then -- hole in way
  429.            [h]:=[i]; 
  430.            h:=i; 
  431.            [i]:=elt_nil 
  432.         end
  433.      end
  434.       end;
  435.       if should_shrink then return halve_size
  436.       else return self
  437.       end
  438.    end;
  439.  
  440.    clear:SAME is
  441.       -- Clear out self, return the space if it has 17 or less entries
  442.       -- otherwise return void. Self may be void.
  443.       if void(self) then return void end;
  444.       if asize<=17 then 
  445.      r::=self; 
  446.      r.hsize:=0;
  447.      loop r.aset!(elt_nil) end;
  448.      return r
  449.       else return void 
  450.       end
  451.    end;
  452.  
  453.    is_empty:BOOL is        
  454.       -- True if the set is empty. Self may be void.
  455.       return (void(self)) or (hsize=0)
  456.    end;
  457.    
  458.    equals(s:SAME):BOOL is    
  459.       -- True if `s' has the same elements as self. Self may be void.
  460.       loop 
  461.      if ~s.test(elt!) then return false end
  462.       end;
  463.       loop 
  464.      if ~test(s.elt!) then return false end
  465.       end;
  466.       return true
  467.    end;
  468.    
  469.    is_disjoint_from(s:SAME):BOOL is
  470.       -- True if self and `s' have no elements in common.
  471.       -- Self may be void.
  472.       loop 
  473.      if s.test(elt!) then return false end
  474.       end;
  475.       return true 
  476.    end;
  477.    
  478.    intersects(s:SAME):BOOL is
  479.       -- True if self and `s' have elements in common.
  480.       -- Self may be void.
  481.       return ~is_disjoint_from(s) 
  482.    end;
  483.    
  484.    is_subset(s:SAME):BOOL is
  485.       -- True if all elements of self are contained in `s'.
  486.       -- Self may be void.
  487.       loop 
  488.      if ~s.test(elt!) then return false end
  489.       end;
  490.       return true 
  491.    end;
  492.    
  493.    to_union(s:SAME):SAME is
  494.       -- The union of self and `s', modifies self.
  495.       -- Self may be void.
  496.       r::=self; 
  497.       loop r:=r.insert(s.elt!) end; 
  498.       return r 
  499.    end;
  500.    
  501.    union(s:SAME):SAME is
  502.       -- A new set which is the union of self and `s'.
  503.       -- Self may be void.
  504.       return copy.to_union(s) 
  505.    end;
  506.    
  507.    to_intersect(s:SAME):SAME is
  508.       -- The intersection of self and `s', modifies self.
  509.       -- Self may be void.  Can't think of a way to do this
  510.       -- in place.
  511.       return intersect(s)
  512.    end;
  513.    
  514.    intersect(s:SAME):SAME is
  515.       -- A new set which is the intersection of self and s.
  516.       -- Self may be void.
  517.       r:SAME;
  518.       loop 
  519.      e::=elt!;
  520.      if s.test(e) then r:=r.insert(e) end 
  521.       end; 
  522.       return r 
  523.    end;
  524.    
  525.    to_difference(s:SAME):SAME is
  526.       -- The difference of self and `s', modifies self.
  527.       -- Self may be void.
  528.       r::=self; 
  529.       loop r:=r.delete(s.elt!) end; 
  530.       return r 
  531.    end;
  532.    
  533.    difference(s:SAME):SAME is
  534.       -- A new set which is the difference between self and `s'.
  535.       -- Self may be void.
  536.       r:SAME;
  537.       loop 
  538.      e::=elt!;
  539.      if ~s.test(e) then r:=r.insert(e) end 
  540.       end; 
  541.       return r 
  542.    end;
  543.    
  544.    to_sym_difference(s:SAME):SAME is
  545.       -- The symmetric difference of self and `s', modifies self.
  546.       -- Self may be void.
  547.       r::=self;
  548.       loop 
  549.      e::=s.elt!;
  550.      if r.test(e) then r:=r.delete(e)
  551.      else r:=r.insert(e)
  552.      end
  553.       end;
  554.       return r
  555.    end;
  556.    
  557.    sym_difference(s:SAME):SAME is
  558.       -- A new set which is the symmetric difference between self 
  559.       -- and `s'. Self may be void.
  560.       r:SAME;
  561.       loop 
  562.      e::=elt!; 
  563.      if ~s.test(e) then r:=r.insert(e) end
  564.       end;
  565.       loop 
  566.      e::=s.elt!; 
  567.      if ~test(e) then r:=r.insert(e) end 
  568.       end;
  569.       return r 
  570.    end;
  571.  
  572.    str: STR is
  573.       res ::= #FSTR("{");
  574.       loop e ::= elt!;
  575.      typecase e
  576.      when $STR then     res := res+",".separate!(e.str) 
  577.      else res := res+",".separate!(SYS::id(e).str) end;
  578.       end;
  579.       res := res+"}";
  580.       return res.str;
  581.    end;
  582.    
  583. end; -- class FSET{T}
  584. -------------------------------------------------------------------
  585.